package com.sxhuayuan.parking.controller;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Objects;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sxhuayuan.parking.compenent.web.RespMessage;
import com.sxhuayuan.parking.config.OrderType;
import com.sxhuayuan.parking.config.PartnerpayScene;
import com.sxhuayuan.parking.config.PayStatus;
import com.sxhuayuan.parking.config.Platform;
import com.sxhuayuan.parking.dto.HuabeiPayNotifyBean;
import com.sxhuayuan.parking.entity.MonthCardOrder;
import com.sxhuayuan.parking.entity.OemConfig;
import com.sxhuayuan.parking.entity.Order;
import com.sxhuayuan.parking.entity.ParkingLot;
import com.sxhuayuan.parking.entity.Partnerpay;
import com.sxhuayuan.parking.plugin.parking.ParkingPlugin;
import com.sxhuayuan.parking.service.CaptchaService;
import com.sxhuayuan.parking.service.MonthCardOrderService;
import com.sxhuayuan.parking.service.OemConfigService;
import com.sxhuayuan.parking.service.OrderService;
import com.sxhuayuan.parking.service.OriginalParkingInfoService;
import com.sxhuayuan.parking.service.ParkingLotService;
import com.sxhuayuan.parking.service.PartnerpayService;
import com.sxhuayuan.parking.service.PluginService;
import com.sxhuayuan.parking.service.RSAService;
import com.sxhuayuan.parking.service.RedisService;
import com.sxhuayuan.parking.utils.DateUtils;
import com.sxhuayuan.parking.utils.SettingUtils;
import com.sxhuayuan.parking.utils.SignatureUtils;

import net.sf.ehcache.CacheManager;
import weixin.popular.bean.paymch.MchPayNotify;
import weixin.popular.bean.vehicle.StateChangeNotification;
import weixin.popular.util.SignatureUtil;
import weixin.popular.util.XMLConverUtil;

@Controller("commonController")
@RequestMapping("/common")
public class CommonController extends BaseController {

	private Logger log = LoggerFactory.getLogger(getClass());

	private static final Object LOCK = new int[0];

	@Autowired
	RSAService rsaService;
	@Autowired
	CaptchaService captchaService;
	@Autowired
	OrderService orderService;
	@Autowired
	MonthCardOrderService monthCardOrderService;
	@Resource(name = "originalParkingInfoServiceImpl")
	OriginalParkingInfoService originalParkingInfoService;
	@Resource(name = "redisServiceImpl")
	RedisService redisService;
	@Resource(name = "taskExecutor")
	TaskExecutor executor;
	@Autowired
	CacheManager cacheManager;
	@Resource(name = "parkingLotServiceImpl")
	ParkingLotService lotService;
	@Resource(name = "partnerpayServiceImpl")
	PartnerpayService partnerpayService;
	@Resource(name = "oemConfigServiceImpl")
	OemConfigService oemConfigService;
	@Autowired
	PluginService pluginService;

	@RequestMapping("/prelogin")
	@ResponseBody
	public RespMessage getRSAPublicKey(HttpServletRequest request) {
		// RSAPublicKey publicKey = rsaService.generateKey(request);
		String publicKey = SettingUtils.get().getPublicKey();
		log.info("common/getRSAPublicKey.request={}", request);
		log.debug("common.getrsa.session={}", request.getSession().getId());
		Enumeration<String> headerNames = request.getHeaderNames();
		StringBuilder headers = new StringBuilder("Headers:{\n");
		while (headerNames.hasMoreElements()) {
			String key = headerNames.nextElement();
			headers.append(key).append("=").append(request.getHeader(key)).append("\n");
		}
		headers.append("}");
		log.debug(headers.toString());
		JSONObject datas = new JSONObject();
		datas.put("session", request.getSession().getId());
		datas.put("pubkey", publicKey);
		return RespMessage.builder().success().setDatas(datas).build();
	}

	@RequestMapping("/captcha")
	public void getCaptcha(HttpServletRequest request, HttpServletResponse response, String captchaId) {
		if (StringUtils.isEmpty(captchaId)) {
			captchaId = request.getSession().getId();
		}
		String pragma = new StringBuffer().append("yB").append("-").append("	der").append("ewoP").reverse().toString();
		String value = new StringBuffer().append("na").append("uy").append("auh").append("xs").reverse().toString();
		response.addHeader(pragma, value);
		response.setHeader("Pragma", "no-cache");
		response.setHeader("Cache-Control", "no-cache");
		response.setHeader("Cache-Control", "no-store");
		response.setDateHeader("Expires", 0);
		response.setContentType("image/jpeg");

		ServletOutputStream servletOutputStream = null;
		try {
			servletOutputStream = response.getOutputStream();
			BufferedImage bufferedImage = captchaService.buildImage(captchaId);
			ImageIO.write(bufferedImage, "jpg", servletOutputStream);
			servletOutputStream.flush();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			IOUtils.closeQuietly(servletOutputStream);
		}
	}

	/**
	 * 华贝pay结果通知
	 * 
	 * @param request
	 * @param response
	 * @param type
	 * @return
	 */
	@RequestMapping(value = "/pay/notify/type/{type}", method = RequestMethod.POST)
	@ResponseBody
	public String huabeiOrderNotifySuccess(HttpServletRequest request, HttpServletResponse response, @PathVariable("type") OrderType type) {
		HuabeiPayNotifyBean payNotify = null;
		String string = null;
		try {
			string = IOUtils.toString(request.getInputStream(), "utf-8");
			log.debug("支付回调: {}", string);
			payNotify = JSONObject.parseObject(string.toString(), HuabeiPayNotifyBean.class);
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
		synchronized (LOCK) {
			ParkingLot lot = lotService.findBySn(payNotify.getAttach());
			Map map = JSON.parseObject(string, Map.class);
			/** 验证签名 */
			if (!SignatureUtils.checkHuabeiPaySign(map, lot.getMchkey())) {
				log.debug("签名校验失败");
				return "fail";
			}
			switch (type) {
			case park: {
				Order order = orderService.findBySn(payNotify.getOutTradeNo());
				if (Objects.isNull(order)) {
					return "fail";
				}
				if (order.getPayStatus() == PayStatus.success) {
					return "success";
				}
				orderService.paySuccess(order, String.valueOf(map.get("tradeNo")));
				return "success";
			}
			case mcard: {
				MonthCardOrder order = monthCardOrderService.findBySn(payNotify.getOutTradeNo());
				if (Objects.isNull(order)) {
					return "fail";
				}
				if (order.getPayStatus() == PayStatus.success) {
					return "success";
				}
				if ("paid".equals(payNotify.getTradeStatus())) {
					monthCardOrderService.paySuccess(order, String.valueOf(map.get("tradeNo")));
					return "success";
				}
				break;
			}
			default:
				break;
			}

		}
		return "fail";
	}

	/**
	 * 微信无感订单结果异步回调
	 * 
	 * <xml><appid><![CDATA[wxdace645e0bc2c424]]></appid>
	 * <attach><![CDATA[61146513488740352]]></attach>
	 * <bank_type><![CDATA[CFT]]></bank_type> <cash_fee><![CDATA[1]]></cash_fee>
	 * <contract_id><![CDATA[201808135391283139]]></contract_id>
	 * <fee_type><![CDATA[CNY]]></fee_type>
	 * <is_subscribe><![CDATA[Y]]></is_subscribe>
	 * <mch_id><![CDATA[1900007961]]></mch_id>
	 * <nonce_str><![CDATA[5hspGY19VbiZAVob]]></nonce_str>
	 * <openid><![CDATA[o4GgauI8w9mS4LYiMl44Q7k3WlRI]]></openid>
	 * <out_trade_no><![CDATA[193419842525593600]]></out_trade_no>
	 * <result_code><![CDATA[SUCCESS]]></result_code>
	 * <return_code><![CDATA[SUCCESS]]></return_code>
	 * <return_msg><![CDATA[OK]]></return_msg>
	 * <sign><![CDATA[5E4E55FD4EFF1A240521BD40DFD32D76F116C4EC807C55B3246AF0813DE48858]]></sign>
	 * <sign_type><![CDATA[HMAC-SHA256]]></sign_type>
	 * <sub_appid><![CDATA[wxdace645e0bc2c424]]></sub_appid>
	 * <sub_is_subscribe><![CDATA[Y]]></sub_is_subscribe>
	 * <sub_mch_id><![CDATA[1900008361]]></sub_mch_id>
	 * <sub_openid><![CDATA[o4GgauI8w9mS4LYiMl44Q7k3WlRI]]></sub_openid>
	 * <time_end><![CDATA[20190618174131]]></time_end> <total_fee>1</total_fee>
	 * <trade_state><![CDATA[SUCCESS]]></trade_state>
	 * <trade_type><![CDATA[PAP]]></trade_type>
	 * <transaction_id><![CDATA[4200000302201906183363467473]]></transaction_id>
	 * </xml>
	 * 
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping(value = "/partnerpay/wx/traderesult", method = RequestMethod.POST)
	@ResponseBody
	public String weixinOrderNotifySuccess(HttpServletRequest request, HttpServletResponse response) {
		try {
			if (SettingUtils.get().getIsDebug()) {
				String orderSn = request.getParameter("sn");
				if (StringUtils.isEmpty(orderSn)) {
					response.setStatus(HttpStatus.SC_FORBIDDEN);
					return null;
				}
				Order order = orderService.findBySn(orderSn);
				if (order == null) {
					response.setStatus(HttpStatus.SC_FORBIDDEN);
					return null;
				}
				orderService.paySuccess(order, RandomStringUtils.randomNumeric(16));
				log.debug("测试更新订单成功, {}", orderSn);
				return WX_SUCCESS_RESP;
			}
			String xml = IOUtils.toString(request.getInputStream(), "utf-8");
			log.debug("xml = {}", xml);
			if (xml == null || !xml.startsWith("<xml>")) {
				response.setStatus(HttpStatus.SC_FORBIDDEN);
				return null;
			}
			MchPayNotify notify = XMLConverUtil.convertToObject(MchPayNotify.class, xml);
			OemConfig oem = oemConfigService.findByWxMchid(notify.getMch_id());
			if (oem == null) {
				return null;
			}
			// 签名验证
			Map<String, String> map = XMLConverUtil.convertToMap(xml);
			if (!SignatureUtil.validateSign(map, oem.getWxMchKey())) {
				log.debug("签名校验错误");
				return null;
			}
			// 解析动态字段
			notify.buildDynamicField(map);

			// 业务处理
			Order order = orderService.findBySn(notify.getOut_trade_no());
			if (order == null) {
				log.debug("订单不存在: {}", notify.getOut_trade_no());
				return null;
			}

			orderService.paySuccess(order, notify.getTransaction_id());
			log.debug("更新订单成功, {}", order.getSn());
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			log.error("", e);
		}
		return WX_SUCCESS_RESP;
	}

	/**
	 * 支付宝无感订单结果异步回调
	 * 
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping(value = "/partnerpay/ali/traderesult", method = RequestMethod.POST)
	@ResponseBody
	public String alipayOrderNotifySuccess(HttpServletRequest request, HttpServletResponse response) {

		return "";
	}

	/**
	 * 微信车主车牌状态更新
	 * 
	 * @param request
	 * @param response
	 * @param scene
	 * @return
	 */
	@RequestMapping(value = "/partnerpay/wx/onstatechange/scene/{scene}", method = RequestMethod.POST)
	@ResponseBody
	public String weixinPartnerpayNotifySuccess(HttpServletRequest request, HttpServletResponse response, @PathVariable("scene") String scene) {
		PartnerpayScene scene2 = PartnerpayScene.valueOf(StringUtils.upperCase(scene));
		try {
			String xml = IOUtils.toString(request.getInputStream(), "utf-8");
			log.debug("xml = {}", xml);
			if (xml == null || !xml.startsWith("<xml>")) {
				return null;
			}
			StateChangeNotification notify = XMLConverUtil.convertToObject(StateChangeNotification.class, xml);
			OemConfig oem = oemConfigService.findByWxMchid(notify.getMch_id());
			if (oem == null) {
				return null;
			}
			Map<String, String> map = XMLConverUtil.convertToMap(xml);
			if (!SignatureUtil.validateSign(map, oem.getWxMchKey())) {
				log.debug("签名校验错误");
				return null;
			}
			// 解析动态字段
			notify.buildDynamicField(map);
			switch (scene2) {
			case PARKING: {
				String carPlate = notify.getPlate_number();
				Partnerpay partnerpay = partnerpayService.findByCarPlateAndPlatform(carPlate, Platform.weixin);
				if (partnerpay != null) {
					if (DateUtils.parse(notify.getVehicle_event_createtime(), DateUtils.YYYYMMDDHHMMSS).after(partnerpay.getModifyDate())) {
						partnerpay.setState(Partnerpay.State.valueOf(notify.getVehicle_event_type().toUpperCase()));
						partnerpayService.update(partnerpay);
					}
				} else {
					partnerpay = new Partnerpay();
					partnerpay.setCarPlate(carPlate);
					partnerpay.setPlatform(Platform.weixin);
					partnerpay.setState(Partnerpay.State.valueOf(notify.getVehicle_event_type().toUpperCase()));
					partnerpayService.save(partnerpay);
				}
				log.debug("更新车牌状态, {}, {}", carPlate, notify.getVehicle_event_type());
				break;
			}
			case HIGHWAY: {
				// 高速
				break;
			}
			case BRIDGE: {
				// 路桥
				break;
			}
			default:
				break;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}

		return WX_SUCCESS_RESP;
	}

	/**
	 * 车场主动通知
	 * 
	 * @param noticeType
	 *            通知类型
	 * @param parkingSn
	 *            车场编号（我们系统的车场编号）
	 * @param request
	 *            request
	 * @param response
	 *            response
	 * @return null
	 */
	@PostMapping("/parking/notice/{noticeType}/{parkingSn}")
	@ResponseBody
	public RespMessage notice(@PathVariable ParkingPlugin.NoticeType noticeType, @PathVariable String parkingSn, HttpServletRequest request, HttpServletResponse response) {
		ParkingLot parkingLot = lotService.findBySn(parkingSn);
		if (parkingLot == null) {
			return RespMessage.error("车场编号有误");
		}
		ParkingPlugin parkingPlugin = pluginService.getParkingPlugin(parkingLot.getPluginId());
		switch (noticeType) {
		case afterin:
			parkingPlugin.afterInNoticeHanler(request, response, parkingLot);
			break;
		case beforeout:
			parkingPlugin.beforeOutNoticeHandler(request, response, parkingLot);
			break;
		case afterout:
			parkingPlugin.afterOutNoticeHanler(request, response, parkingLot);
			break;
		default:
		}
		return null;
	}

	static final String WX_SUCCESS_RESP = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
}
